O trabalho tem como propósito aplicar técnicas de ciência de dados na análise de uma base real de morbilidade hospitalar, a base de Grupos de Diagnóstico Homogéneo (GDH) disponibilizada pela Administração Central do Sistema de Saúde (ACSS). A crescente complexidade dos cuidados hospitalares e a transição para o modelo das Unidades Locais de Saúde (ULS) colocam desafios importantes para a gestão integrada dos recursos e para a equidade no acesso. Neste contexto, comparar realidades distintas (como as ULS do Médio Ave e de Amadora-Sintra) permite compreender diferenças territoriais na carga de doença e na resposta dos serviços hospitalares, contribuindo para uma visão mais informada sobre o desempenho do SNS. Assim, este estudo combina análise demográfica, epidemiológica e operacional, explorando a base de dados de internamentos hospitalares (GDH) e relacionando-a com variáveis geográficas e populacionais. O objetivo final é demonstrar o potencial da análise de dados em R como ferramenta de apoio à tomada de decisão em saúde pública e à avaliação do desempenho das ULS.
1.0.1 A ULS
imagem
Caracterizar a população residente nas áreas correspondentes às duas ULS (população 2017)
O projecto centra-se na análise comparativa da situação nas ULS do Médio Ave e Amadora-Sintra.
Analisar e comparar os padrões de morbilidade hospitalar e a resposta assistencial entre as Unidades Locais de Saúde (ULS) do Médio Ave e Amadora-Sintra, utilizando dados da base de Grupos de Diagnóstico Homogéneo (GDH) do SNS, com foco na caracterização demográfica, perfil de diagnósticos e desempenho hospitalar. Objetivos específicos
Caracterizar a população residente nas áreas correspondentes às duas ULS, segundo idade, sexo e perfil de morbilidade.
Identificar e comparar os principais grupos de diagnósticos (GDH) e condições de saúde mais prevalentes em cada região.
Avaliar diferenças entre ULS
limitações de codificação e de qualidade dos dados.
1.3 2.2. Objetivos específicos
Caracterizar a população residente nos concelhos correspondentes às áreas das ULS Amadora/Sintra
distribuição idade e sexo
concelho
Caracterizar os problemas de saúde e identificar os mais frequentes (base)
hora_urgencia: n(1.327.998) - vamos usar? se não apagar
severidade: n(225) em branco -> transformar em “desconhecido”
mortalidade n(225) em branco -> “NA” - transformar em desconhecido para proporções
Erros tipo variaveis
gcd_apr31 - int devia ser chr
concelho e distrito - estão como int - sao codigos numéricos deve ser chr
freguesia - remover, sem valores que possamos utilizar
Código
# mapeia valores presentes na base de dados de categorias de variávies chr gdh_unique <- gdh_base_raw |>select(where(is.character)) |>map(unique)
Outros:
dias internamento - como interpretar? remover 0?
o que seria expectavel (dicionario) vs obs variaveis
adm_tip - apenas dois tipos, mas 0 missings
dsp - como interpretar? tratar falecidos
seq_number - sem NA
hosp_id - 56 possiveis - algum missing?
sexo - 3 variaveis como esperado,
idade - todas têm entrada - 0 são mesmo idade? se tiver meses?
distrito - transformar em chr e contar diferentes (30 valores possiveis)
concelho - igual a distrito
freguesia - inútil - remover
hora_entrada - valores em s, a partir das 0h do dia da entrada na instituição - verificar 0 e como interpretar
dias_int - Total de dias de estadia do utente na instituição de saúde, em conformidade com a definição estatística de tempo de internamento, constante na portaria em vigor à data de extração dos dados.- qual a definicao estatistica?
dsp - 9 valores possiveis, 9 entradas , contar "Desconhecido" como NA
adm_tip - 8 valores possiveis, apenas 2 , 0 NAs
hora_urgência - Hora de entrada no serviço de urgência da instituição de saúde. Os valores são apresentados em segundos, contados a partir das zero horas do dia em que o utente deu entrada, no serviço de urgência da instituição -
gcd_APR31 - mudar para chr, 27 valores possiveis, 99 - Erro
tipo_port APR31 - 2 possiveis, 0 NA - bem
severidade_APR31 - mortalidade_APR31 - 4 valores possiveis existem 5 - 225 NA são todos missing
cod_diagnostico - ver se dao todos match com icd10.csv
Statistic Value
1 Min 0.000000e+00
2 Max 1.090000e+02
3 Mean 5.667767e+01
4 Median 6.300000e+01
5 Total 8.842646e+07
6 NAs 0.000000e+00
7 Quantile_0% 0.000000e+00
8 Quantile_25% 4.300000e+01
9 Quantile_50% 6.300000e+01
10 Quantile_75% 7.500000e+01
11 Quantile_100% 1.090000e+02
Código
# Base dados completap4_0 <- gdh_base_clean |>ggplot() +geom_boxplot(aes(y = idade) ) +# facet_grid(~sexo) +theme_minimal() +theme(axis.line.x =element_blank(),axis.text.x =element_blank() )p4_0
# total_uls_sex_age <- gdh_uls |>group_by(uls_2024, adm_tip, sexo =as.factor(sexo), idade_cat) %>%summarise(total =n()) %>%arrange(sexo)tabela4 <-tbl_summary( gdh_uls,include =c(uls_2024, adm_tip, sexo, idade_cat),by = sexo, # Dividir a tabela pelo estado da doença cardíacamissing ="ifany", # Excluir dados ausentes do resumo) |>modify_spanning_header(c("stat_1", "stat_2") ~"**Sexo**") %>%add_n() |># Adicionar uma coluna para contar observações não ausentes# add_p() |> # Realizar testes estatísticos para comparar gruposmodify_header(label ="**Variável**") |># Personalizar o cabeçalho da tabelabold_labels() # Tornar as etiquetas em negrito para ênfasetabela4 <- tabela4 |>as_gt() |>tab_header(title =md("**Episódios por ULS**") ,subtitle ="Por sexo" ) |>tab_source_note(source_note =md("Fonte: gdh") ) |>fmt_number( decimals =3) |>opt_stylize(style =1, color ="gray") |>opt_align_table_header(align ="left") tabela4
Episódios por ULS
Por sexo
Variável
N
Sexo
Feminino
N = 64,2311
Masculino
N = 58,6171
uls_2024
122,848
ULS de Amadora/Sintra
43,417 (68%)
38,384 (65%)
ULS do Médio Ave
20,814 (32%)
20,233 (35%)
adm_tip
122,848
Programada
40,687 (63%)
39,674 (68%)
Urgente
23,544 (37%)
18,943 (32%)
idade_cat
122,848
[0,18)
6,305 (9.8%)
7,615 (13%)
[18,65)
34,209 (53%)
24,021 (41%)
[65,Inf)
23,717 (37%)
26,981 (46%)
1 n (%)
Fonte: gdh
Código
## Deixar por sexo, retirar esta # tabela2 <- tbl_summary(# gdh_uls,# include = c(uls_2024, adm_tip, sexo, idade_cat_ine, dsp, descricao_apr31),# by = uls_2024, # Dividir a tabela pelo estado da doença cardíaca# missing = "ifany", # Excluir dados ausentes do resumo# ) |># modify_spanning_header(c("stat_1", "stat_2") ~ "**ULS**") %>%# add_n() |> # Adicionar uma coluna para contar observações não ausentes# # add_p() |> # Realizar testes estatísticos para comparar grupos# modify_header(label = "**Variável**") |> # Personalizar o cabeçalho da tabela# bold_labels() # Tornar as etiquetas em negrito para ênfase# # tabela2 <- tabela2 |> # as_gt() |> # tab_header(# title = md("**Risco por ULS**") ,# subtitle = "Por sexo e idade"# ) |># tab_source_note(# source_note = md("Fonte: gdh")# ) |># fmt_number( decimals = 3) |> # opt_stylize(style = 1, color = "gray") |> # opt_align_table_header(align = "left") # # tabela2# Contar total de observações por grupo etáriocontagem_idade <- gdh_uls %>%group_by(uls_2024, as.factor(sexo), idade_cat) %>%summarise(total =n()) %>%arrange(idade_cat)# p5 <- total_ep_uls |> # ggplot() + # geom_bar(aes(x = adm_tip, fill = sexo), # stat = "count") + # geom_text(# aes(x = adm_tip),# label = "total",# stat = "identity",# position = position_stack(vjust = 0.5)# ) +# facet_wrap(~uls_2024) + # Dividir o gráfico em facetas com base na variável 'tipo_de_especialidade'# theme_classic()# # p5
5.0.3 Proporções
Código
# grafico barras por uls e severidade problema - considerar fazer dois separados "dodge" # como fazer aparecer por percentagens? p6 <- gdh_uls |>count(uls_2024, severidade_apr31) |>mutate(freq = (n /sum(n))) |>mutate(cum =cumsum(freq)) |>ggplot(aes(x = uls_2024, y = freq, fill = severidade_apr31) )+geom_bar(position ="stack", stat ="identity") +scale_fill_viridis_d(end = .5) +geom_text(aes(label =percent(freq, accuracy = .1)), position =position_stack(vjust = .1), colour ="white") +labs(fill ="severidade_apr31", y ="Proportion", x ="ULS 2024")# low hanging fruit: residentes municipio (INE) 2017 - # NAs - tirar valores; retirar variaveis?; # merge()# fazer tabela com os missings p6
Código
## !!! transformar em função
5.1 Perfil de morbilidade
Código
# total_mort_apr31 <- gdh_uls |># mutate(# mort_cat = factor(mortalidade_apr31)# ) |> # group_by(uls_2024, mort_cat) |> # summarise(total = n(), .groups = "drop") |> # arrange(uls_2024)total_mort_apr31 <- gdh_uls |>mutate(mortalidade_apr31 =na_if(mortalidade_apr31, ""), # transforma "" em NAmort_cat =fct_explicit_na(factor(mortalidade_apr31), na_level ="NA") ) |>group_by(uls_2024, mort_cat) |>summarise(total =n(), .groups ="drop")p7 <- total_mort_apr31 |>ggplot(aes(x = uls_2024, y = total, fill = mort_cat) )+geom_bar(position ="stack", stat ="identity") +scale_fill_viridis_d(end =0.5) +geom_text(aes(label = total), position =position_stack(vjust =1), colour ="white") +labs(y ="Total de episódios", x ="ULS", fill ="Severidade")p7